
package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.bo.ProductBO;
import com.yami.shop.bean.dto.ProdAndSkuListsDto;
import com.yami.shop.bean.enums.*;
import com.yami.shop.bean.event.*;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.param.*;
import com.yami.shop.bean.vo.PersonnftProdVo;
import com.yami.shop.common.bean.SysProdConfig;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.constants.CacheNames;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.*;
import com.yami.shop.dao.*;
import com.yami.shop.manager.impl.LangManager;
import com.yami.shop.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.regex.Pattern.compile;

/**
 * @author yami
 */
@Service
@AllArgsConstructor
@Slf4j
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    private final ProductMapper productMapper;
    private final ProdLangService prodLangService;
    private final ApplicationContext applicationContext;
    private final SkuService skuService;
    private final BasketMapper basketMapper;
    private final SkuMapper skuMapper;
    private final UserCollectionService userCollectionService;
    private final SkuLangMapper skuLangMapper;
    private final OfflineHandleEventService offlineHandleEventService;
    private final OrderMapper orderMapper;
    private final OrderItemMapper orderItemMapper;
    private final OrderRefundMapper orderRefundMapper;
    private final FlowPageAnalysisMapper flowPageAnalysisMapper;
    private final FlowLogService flowLogService;
    private final FlowUserAnalysisMapper flowUserAnalysisMapper;

    private final ApplicationEventPublisher eventPublisher;
    private final ProdParameterService prodParameterService;
    private final SysConfigService sysConfigService;
    private final ProdExtensionService prodExtensionService;
    private final AttachFileService attachFileService;
    private final ProdNftService prodNftService;
    private final ProdLevelService prodLevelService;
    private final LangManager langManager;
    private final ShopDetailService ShopDetailService;
    private final ProdModelService prodModelService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveProduct(ProductParam productParam) {
        if(Objects.isNull(productParam.getStatus())){
            productParam.setStatus(ProdStatusEnums.NORMAL.getValue());
        }
        checkProdLang(productParam.getProdLangList());
        Product product = BeanUtil.map(productParam, Product.class);
        // 店铺商品-判断是否需要进行审核
        if (!Objects.equals(product.getShopId(), Constant.PLATFORM_SHOP_ID)) {
            // 判断一下商品审核开关，开着的话默认新发布商品处于待审核状态4
            SysProdConfig sysProdConfig = sysConfigService.getSysConfigObject(Constant.PROD_SWITCH_CONFIG, SysProdConfig.class);
            product.setStatus(BooleanUtil.isTrue(sysProdConfig.getProdAudit()) ? ProdStatusEnums.AUDIT.getValue() : productParam.getStatus());
        } else {
            product.setStatus(productParam.getStatus());
        }
        product.setDeliveryMode(Json.toJsonString(productParam.getDeliveryModeVo()));
        product.setUpdateTime(new Date());
        product.setPutawayTime(new Date());
        product.setCreateTime(new Date());
        product.setVersion(0);
        if (Objects.isNull(productParam.getMold()) || Objects.equals(productParam.getMold(), ProdType.PROD_TYPE_NORMAL.value())) {
            product.setIsRefund(null);
            product.setWriteOffTime(null);
            product.setWriteOffStart(null);
            product.setWriteOffEnd(null);
            product.setWriteOffNum(null);
            product.setWriteOffMultipleCount(null);
            product.setVirtualRemark(null);
        } else if(Objects.isNull(productParam.getMold()) || Objects.equals(productParam.getMold(), ProdType.PROD_TYPE_GROUP.value())) {
            product.setMold(1);
        } else if(Objects.isNull(productParam.getMold()) || Objects.equals(productParam.getMold(), ProdType.PROD_TYPE_SECKILL.value())) {
            //数字商品
            product.setMold(2);
        }
        product.setActivityId(0L);
        // 获取该店铺渠道CODE
        ShopDetail shopDetailByShopId = ShopDetailService.getShopDetailByShopId(productParam.getShopId());
        product.setChannelCode(shopDetailByShopId.getChannelCode());

        productMapper.insert(product);
        // 创建二维码 -- 商品详情
        createQrcode(product.getProdId(),product.getShopId());
        if(!Objects.isNull(productParam.getMold()) && (Objects.equals(productParam.getMold(), ProdType.PROD_TYPE_SECKILL.value()) || Objects.equals(productParam.getMold(), ProdType.PROD_TYPE_BOX.value()))) {
            // 保存数字商品信息
            ProdNft prodNft = BeanUtil.map(productParam.getVirtualProductForm(), ProdNft.class);
            prodNft.setProdId(product.getProdId());
            prodNftService.save(prodNft);
            if(productParam.getVirtualProductForm().getIsScan() == 1){
                ProdModel prodModel = new ProdModel();
                prodModel.setProdId(product.getProdId());
                prodModel.setScanType("1");
                prodModel.setScanModel(productParam.getVirtualProductForm().getScanModel());
                prodModel.setScanImg(productParam.getVirtualProductForm().getScanImg());
                prodModelService.save(prodModel);
            }

        }
        // 保存语言表
        productParam.setProdId(product.getProdId());
        Integer prodStock = 0;
        // 保存商品参数
        prodParameterService.saveAndUpdateParameter(productParam.getProdParameterList(), productParam.getProdId());
        if (CollectionUtil.isNotEmpty(product.getSkuList())) {
            List<Sku> skuList = product.getSkuList();
            setSkuName(productParam.getProdLangList(), skuList);
            Long prodId = productParam.getProdId();
            for (Sku sku : skuList) {
                if (Objects.equals(sku.getStatus(), 1)) {
                    prodStock += sku.getStocks();
                }
                sku.setProdId(prodId);
            }

            skuService.insertBatchAndLang(skuList);
            // 普通商品记录库存初始化
            StockBillLog stockBillLog = new StockBillLog();
            stockBillLog.setShopId(product.getShopId());
            stockBillLog.setEmployeeId(productParam.getEmployeeId());
            stockBillLog.setMakerMobile(productParam.getEmployeeMobile());
            stockBillLog.setStockBillType(StockBillType.INITIALIZE.value());
            applicationContext.publishEvent(new StockBillChangeEvent(stockBillLog, product.getSkuList()));
        }
        saveLang(productParam);
        ProdExtension prodExtension = new ProdExtension();
        prodExtension.setProdId(product.getProdId());
        prodExtension.setActualStock(prodStock);
        prodExtension.setStock(prodStock);
        prodExtensionService.save(prodExtension);
    }

    private void createQrcode(Long prodId,Long shopId) {
        QrConfig config = new QrConfig(300,300);
        BufferedImage qrgenerate = QrCodeUtil.generate(sysConfigService.getValue("V_URL")+"/#/?shopId="+shopId+"&prodId="+prodId, config);
        //保存图片
        ByteArrayOutputStream qrOutputStream = new ByteArrayOutputStream();
        //读文件
        try {
            ImageIO.write(qrgenerate,"jpg",qrOutputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        MultipartFile ossMultipartFile = new OssMultipartFile("111.jpg", ".jpg", qrOutputStream.toByteArray());
        try {
            String fileName = attachFileService.uploadFile(ossMultipartFile.getBytes(), UUID.fastUUID()+".jpg");
            // 获取微发行链接地址
            sysConfigService.getValue("V_URL");
            // 保存链接信息
            UpdateWrapper<Product> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("prod_id",prodId);
            updateWrapper.set("link_addr",sysConfigService.getValue("V_URL")+"/#/?shopId="+shopId+"&prodId="+prodId);
            updateWrapper.set("qrcode_addr",fileName);
            this.update(updateWrapper);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProduct(ProductParam productParam, Product dbProduct) {
        // 没有品牌的商品，品牌id设为0
        if (Objects.isNull(productParam.getBrandId())) {
            productParam.setBrandId(0L);
        }
        checkProdLang(productParam.getProdLangList());
        Product product = BeanUtil.map(productParam, Product.class);
        product.setDeliveryMode(Json.toJsonString(productParam.getDeliveryModeVo()));
        product.setUpdateTime(new Date());


        List<Sku> insertSkuList = new ArrayList<>();
        // 原有sku增加库存的sku列表(不包含新增的sku)
        List<Sku> addStockSkuList = new ArrayList<>();
        // 原有sku减少库存的sku列表(不包含新增的sku)
        List<Sku> reduceStockSkuList = new ArrayList<>();
        List<Long> deleteSkuIds = new ArrayList<>();            // 删除商品对应语言信息列表
        prodLangService.remove(new LambdaQueryWrapper<ProdLang>().eq(ProdLang::getProdId, product.getProdId()));
        // 保存语言表信息
        saveLang(productParam);
        if (dbProduct.getSource() == 0) {
            List<Long> dbSkuIds = dbProduct.getSkuList().stream().map(Sku::getSkuId).collect(Collectors.toList());
            Map<Long, Sku> dbSkuMap = dbProduct.getSkuList().stream().collect(Collectors.toMap(Sku::getSkuId, dbSku -> dbSku));
            // 将所有该商品的sku标记为已删除状态
            skuMapper.deleteByProdId(product.getProdId());
            // 保存商品参数
            prodParameterService.saveAndUpdateParameter(productParam.getProdParameterList(), productParam.getProdId());
            // 接口传入sku列表
            List<Sku> skuList = product.getSkuList();
            if (CollectionUtil.isEmpty(skuList)) {
                return;
            }
            // 是否有sku的状态发生变化
            boolean skuStatusChangeFlag = false;
            setSkuName(productParam.getProdLangList(), skuList);
            skuStatusChangeFlag = updateProdSku(dbProduct, product, dbSkuIds, dbSkuMap, skuList, skuStatusChangeFlag, insertSkuList, addStockSkuList, reduceStockSkuList);
            // 更新商品库存
            prodExtensionService.updateProdStocks(productParam.getProdId());
            stockBillLogChange(productParam, product, insertSkuList, addStockSkuList, reduceStockSkuList);
            List<Long> existSkuId = skuList.stream().map(Sku::getSkuId).collect(Collectors.toList());
            for (Long dbSkuId : dbSkuIds) {
                if (!existSkuId.contains(dbSkuId)) {
                    deleteSkuIds.add(dbSkuId);
                }
            }
            if (CollUtil.isNotEmpty(insertSkuList) || CollUtil.isNotEmpty(deleteSkuIds) || skuStatusChangeFlag) {
                // 规格发生变化，查看该商品是否参与了套餐活动，正在参与套餐或赠品活动的商品不能修改规格
                GetComboProdCountEvent getComboProdCountEvent = new GetComboProdCountEvent();
                getComboProdCountEvent.setProdId(product.getProdId());
                applicationContext.publishEvent(getComboProdCountEvent);
                if (getComboProdCountEvent.getCount() > 0) {
                    throw new YamiShopBindException("商品正在参与套餐活动，不能修改规格");
                }
                GetGiveawayProdCountEvent getGiveawayProdCountEvent = new GetGiveawayProdCountEvent();
                getGiveawayProdCountEvent.setProdId(product.getProdId());
                getGiveawayProdCountEvent.setGiveawayProdType(2);
                applicationContext.publishEvent(getGiveawayProdCountEvent);
                if (getGiveawayProdCountEvent.getCount() > 0) {
                    throw new YamiShopBindException("商品正在参与赠品活动，不能修改规格");
                }
            }
            // 需要删除的skuIds对应的购物车
            deleteShopCart(dbSkuIds, skuList);
        }

        // 更新商品信息
        // 更新虚拟商品信息
        if(product.getMold().equals(ProdType.PROD_TYPE_SECKILL.value())){
            prodNftService.updateById(product.getVirtualProductForm());
            if(productParam.getVirtualProductForm().getIsScan() == 1){
                prodModelService.update(Wrappers.lambdaUpdate(ProdModel.class)
                        .set(ProdModel::getScanModel,productParam.getVirtualProductForm().getScanModel())
                        .set(ProdModel::getScanImg,productParam.getVirtualProductForm().getScanImg())
                        .eq(ProdModel::getProdId,product.getProdId()));
            }
        }
        saveOrUpdate(product);
        // 删除sku关联信息
        if(dbProduct.getSource() == 0){
            applicationContext.publishEvent(new SkuDeleteEvent(deleteSkuIds));
        }

        // 如果修改成预售商品，则删除用户的购物车中的当前商品
        if (Objects.nonNull(product.getPreSellStatus()) && Objects.equals(product.getPreSellStatus(), 1)) {
            basketMapper.delete(new LambdaQueryWrapper<Basket>().eq(Basket::getProdId, product.getProdId()));
        }
        removeProdCacheByProdId(dbProduct.getProdId());
    }
    @Override
    public void updateWaterSaleNum(Integer waterSoldNum, Long prodId) {
        prodExtensionService.updateWaterSoldNum(waterSoldNum, prodId);
        prodExtensionService.removeProdExtensionCache(prodId);
    }

    /**
     * 删除sku时，删除掉关联购物车
     *
     * @param dbSkuIds 数据库sku信息
     * @param skuList  此时修改后的信息
     */
    private void deleteShopCart(List<Long> dbSkuIds, List<Sku> skuList) {
        List<Long> deleteSkuIds = new ArrayList<>();
        List<Long> existSkuId = skuList.stream().map(Sku::getSkuId).collect(Collectors.toList());
        for (Long dbSkuId : dbSkuIds) {
            if (!existSkuId.contains(dbSkuId)) {
                deleteSkuIds.add(dbSkuId);
            }
        }
        // 如果不为空，则进行删除关联的购物车
        if (CollectionUtils.isNotEmpty(deleteSkuIds)) {
            for (Long deleteSkuId : deleteSkuIds) {
                basketMapper.delete(new LambdaQueryWrapper<Basket>().eq(Basket::getSkuId, deleteSkuId));
            }
        }
    }

    /**
     * 这里的缓存 1800秒消失，详情RedisCacheConfig这里的配置
     * 当秒杀的时候，并不更新这里的缓存，所以库存会滞后，但是半个小时后缓存消失，又会重新获取
     *
     * @param prodId
     * @return
     */
    @Override
    @Cacheable(cacheNames = CacheNames.PRODUCT_KEY, key = "#prodId")
    public Product getProductByProdId(Long prodId) {
        Product product = productMapper.selectByIdAndLang(prodId);
        langManager.getProdAndLang(product);
        return product;
    }


    @Override
    public Product getProductAndLang(Long prodId) {
        ProductServiceImpl productService = (ProductServiceImpl) AopContext.currentProxy();
        Product product = productService.getProductByProdId(prodId);
        langManager.handleProdLang(product);
        return product;
    }

    @Override
    public Product getProductInfo(Long prodId) {
        Product product = this.getProductAndLang(prodId);
        if(product.getSource() == 0){
            // 获取库存
            ProdExtension prodExtension = prodExtensionService.getByProdId(prodId);
            product.setTotalStocks(prodExtension.getStock());
            product.setWaterSoldNum(prodExtension.getWaterSoldNum());
            product.setSoldNum(prodExtension.getSoldNum());
            // 获取规格信息
            List<Sku> skuList = skuMapper.getProdDetailSkuInfo(prodId);
            product.setSkuList(skuList);
        }
        return product;
    }

    @Override
    public Product getProductById(Long prodId) {
        return getProductInfo(prodId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeProductByProdId(Long prodId) {
        Product dbProduct = getProductByProdId(prodId);
        // 将商品的状态变成-1（逻辑删除）
        Product product = new Product();
        product.setProdId(prodId);
        product.setIsTop(0);
        product.setStatus(-1);
        saveOrUpdate(product);
        skuMapper.deleteByProdId(prodId);
        //删除用户收藏中的该商品
        userCollectionService.remove(new LambdaQueryWrapper<UserCollection>()
                .eq(UserCollection::getProdId, prodId));
        // 删除语言表信息
        prodLangService.remove(new LambdaUpdateWrapper<ProdLang>().eq(ProdLang::getProdId, prodId));
        skuLangMapper.deleteByProdId(prodId);
        // 删除商品参数
        prodParameterService.removeByProdId(prodId);
        // 删除商品时，改变分销设置,团购订单处理。。。
        applicationContext.publishEvent(new ProdChangeEvent(dbProduct));
        // 清除缓存
        removeProdCacheByProdId(prodId);
    }

    @Override
    public void removeProdCacheByProdId(Long prodId) {
        if (Objects.isNull(prodId)) {
            return;
        }
        removeProductCacheByProdIds(Collections.singletonList(prodId));
    }

    @Override
    public void removeProductCacheByProdIds(List<Long> prodIds) {
        if (CollUtil.isEmpty(prodIds)) {
            return;
        }
        List<String> keys = new ArrayList<>();
        for (Long prodId : prodIds) {
            // cacheNames = "product"
            keys.add(CacheNames.PRODUCT_KEY + CacheNames.UNION + prodId);
            // cacheNames = "skuList"
            keys.add(CacheNames.SKU_LIST_KEY + CacheNames.UNION + prodId);
            // cacheNames = "prodExtensionInfo"
            keys.add(CacheNames.PROD_EXTENSION_INFO_KEY + CacheNames.UNION + prodId);
            // cacheNames = "prodNftInfo"
            keys.add(CacheNames.PRODUCT_NFT_KEY + CacheNames.UNION + prodId);
        }
        RedisUtil.del(keys);

    }

    @Override
    public void removeProdExtensionCache(Long prodId) {
        prodExtensionService.removeProdExtensionCache(prodId);
    }

    @Override
    public List<ProdAndSkuListsDto> getProdAndSkuLists(List<Long> prodIds) {
        return productMapper.getProdAndSkuLists(prodIds);
    }

    @Override
    public int updateProductToGroup(Long groupActivityId, Long prodId) {
        return productMapper.updateProductToGroup(groupActivityId, prodId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditApply(Long eventId, Long prodId, String reapplyReason) {
        // 更新商品为待审核状态
        productMapper.updateToApply(prodId);
        // 更新事件状态
        offlineHandleEventService.updateToApply(eventId, reapplyReason);
        Product product = new Product();
        product.setProdId(prodId);
        product.setStatus(ProdStatusEnums.PLATFORM_AUDIT.getValue());
        // 商品状态改变时的发送事件
        applicationContext.publishEvent(new ProdChangeStatusEvent(product, product.getStatus()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void prodAudit(OfflineHandleEventAuditParam offlineHandleEventAuditParam, Long sysUserId) {
        // 审核通过,更新商品状态
        Product product = new Product();
        Product dbProduct = this.getProductAndLang(offlineHandleEventAuditParam.getHandleId());
        product.setProdId(offlineHandleEventAuditParam.getHandleId());
        if(Objects.equals(dbProduct.getStatus(), ProdStatusEnums.DELETE.getValue())){
            throw new YamiShopBindException("商品状态已发生改变，请刷新页面");
        }
        if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())) {
            productMapper.updateToShopOffline(offlineHandleEventAuditParam.getHandleId());
            product.setStatus(ProdStatusEnums.SHOP_OFFLINE.getValue());
        } else if (Objects.equals(offlineHandleEventAuditParam.getStatus(), OfflineHandleEventStatus.DISAGREE_BY_PLATFORM.getValue())) {
            productMapper.updateToOffline(offlineHandleEventAuditParam.getHandleId());
            product.setStatus(ProdStatusEnums.PLATFORM_OFFLINE.getValue());
        }
        // 商品状态改变时的发送事件，让活动下线
        applicationContext.publishEvent(new ProdChangeStatusEvent(product, product.getStatus()));
        offlineHandleEventService.auditOfflineEvent(offlineHandleEventAuditParam, sysUserId);
        //发送商品审核提醒给商家
        NotifyTemplateParam shopParam = new NotifyTemplateParam();
        shopParam.setShopId(dbProduct.getShopId());
        shopParam.setProdId(offlineHandleEventAuditParam.getHandleId());
        shopParam.setProdName(dbProduct.getProdName());
        shopParam.setSendType(SendType.PRODUCT_AUDIT.getValue());
        applicationContext.publishEvent(new SendMessageEvent(shopParam));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void offline(Long prodId, String offlineReason, Long sysUserId) {
        Product product = getProductByProdId(prodId);

        // 添加下线处理记录
        Date now = new Date();
        OfflineHandleEvent offlineHandleEvent = new OfflineHandleEvent();
        offlineHandleEvent.setHandleType(OfflineHandleEventType.PROD.getValue());
        offlineHandleEvent.setHandleId(product.getProdId());
        offlineHandleEvent.setHandlerId(sysUserId);
        offlineHandleEvent.setOfflineReason(offlineReason);
        offlineHandleEvent.setCreateTime(now);
        offlineHandleEvent.setShopId(product.getShopId());
        offlineHandleEvent.setStatus(OfflineHandleEventStatus.OFFLINE_BY_PLATFORM.getValue());
        offlineHandleEvent.setUpdateTime(now);
        offlineHandleEventService.save(offlineHandleEvent);

        // 更新活动状态为下线
        productMapper.updateToOffline(prodId);
    }

//    @Override
//    public IPage<Product> getPageAngShopName(PageParam<Product> page, ProductParam product) {
//        return productMapper.getPageAndShopName(page, product);
//    }


    @Override
    public List<ProdAnalysisDataParam> getProdTrendAnalysis(ProdAnalysisSurveyParam param) {
        List<ProdAnalysisDataParam> datas = new ArrayList<>();
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        // 商品访客数列表
        List<ProdAnalysisDataParam> prodVisitorList = flowUserAnalysisMapper.countProdVisitorNum(param);
        Map<String, ProdAnalysisDataParam> prodVisitorMap = prodVisitorList.stream().collect(Collectors.toMap(ProdAnalysisDataParam::getCurrentDay, p -> p));
        //数据统计列表
        List<ProdAnalysisDataParam> flowUserAnalysisList = flowUserAnalysisMapper.analysisSurvey(param);
        Map<String, ProdAnalysisDataParam> flowUserAnalysisMap = flowUserAnalysisList.stream().collect(Collectors.toMap(ProdAnalysisDataParam::getCurrentDay, p -> p));
        // 新增商品数量列表
        List<ProdAnalysisDataParam> newProdList = productMapper.listNewProdByTime(param);
        Map<String, Long> newProdMap = newProdList.stream().collect(Collectors.toMap(ProdAnalysisDataParam::getCurrentDay, ProdAnalysisDataParam::getNewProd));
        //订单统计列表
        List<ProdAnalysisDataParam> prodSurveyList = orderMapper.prodSurveyList(param);
        Map<String, ProdAnalysisDataParam> prodSurveyMap = prodSurveyList.stream().collect(Collectors.toMap(ProdAnalysisDataParam::getCurrentDay, p -> p));
        while (startTime.getTime() <= endTime.getTime()) {
            String date = DateUtils.dateToStrYmd(startTime);
            ProdAnalysisDataParam prodAnalysisDataParam = new ProdAnalysisDataParam();
            prodAnalysisDataParam.setCurrentDay(date);
            if (prodVisitorMap.containsKey(date)) {
                prodAnalysisDataParam.setVisitor(prodVisitorMap.get(date).getVisitor());
            }
            if (flowUserAnalysisMap.containsKey(date)) {
                prodAnalysisDataParam.setVisitedProd(flowUserAnalysisMap.get(date).getVisitedProd());
                prodAnalysisDataParam.setAddCart(flowUserAnalysisMap.get(date).getAddCart());
                prodAnalysisDataParam.setBrowse(flowUserAnalysisMap.get(date).getBrowse());
                prodAnalysisDataParam.setShareVisit(flowUserAnalysisMap.get(date).getShareVisit());
            }
            if (prodSurveyMap.containsKey(date)) {
                prodAnalysisDataParam.setDynamicSale(prodSurveyMap.get(date).getDynamicSale());
                prodAnalysisDataParam.setPayNum(prodSurveyMap.get(date).getPayNum());
                prodAnalysisDataParam.setOrderNum(prodSurveyMap.get(date).getOrderNum());
            }
            startTime = DateUtil.offsetDay(startTime, 1);
            param.setDateTime(endTime);
            // 在架商品数据
            if (newProdMap.containsKey(date)) {
                prodAnalysisDataParam.setNewProd(newProdMap.get(date));
            } else {
                prodAnalysisDataParam.setNewProd(0L);
            }
            datas.add(prodAnalysisDataParam);
        }
        return datas;
    }

    @Override
    public IPage<ProdEffectRespParam> pageProdEffect(PageParam<Product> page, ProdEffectParam param, Integer lang, boolean allProd) {
        // 查询出在架商品
        Integer status = param.getStatus();
        if (Objects.isNull(status)) {
            param.setStatus(0);
        }
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        Set<Long> prodIdSet = getFlowProdId(param.getDateType(), startTime, endTime, param.getShopId());
        IPage<ProdEffectRespParam> pages = new Page<>();
        List<ProdEffectRespParam> respParams = productMapper.getProdEffectByParam(param, prodIdSet);
        param.setStatus(status);
        List<Long> prodIds = new ArrayList<>();
        if (CollUtil.isEmpty(prodIdSet)) {
            return pages;
        }
        prodIds.addAll(prodIdSet);
        List<ProdEffectRespParam> prodFlowList = getProdFlowData(param.getDateType(), prodIds, startTime, endTime);

        List<ProdEffectRespParam> prodOrderList = orderItemMapper.getProdEffectByDateAndProdIds(prodIds, startTime, endTime);

        List<ProdEffectRespParam> prodOrderRefundList = orderRefundMapper.getProdEffectByDateAndProdIds(prodIds, startTime, endTime);

        Map<Long, ProdEffectRespParam> prodFlowMap = prodFlowList.stream().collect(Collectors.toMap(ProdEffectRespParam::getProdId, p -> p));
        Map<Long, ProdEffectRespParam> prodOrderMap = prodOrderList.stream().collect(Collectors.toMap(ProdEffectRespParam::getProdId, p -> p));
        Map<Long, ProdEffectRespParam> prodOrderRefundMap = prodOrderRefundList.stream().collect(Collectors.toMap(ProdEffectRespParam::getProdId, p -> p));
        Iterator<ProdEffectRespParam> iterator = respParams.iterator();
        while (iterator.hasNext()) {
            ProdEffectRespParam respParam = iterator.next();
            // 商品相关数据
            ProdEffectRespParam prodFlowParam = prodFlowMap.get(respParam.getProdId());

            //订单相关
            ProdEffectRespParam prodOrderParam = prodOrderMap.get(respParam.getProdId());

            //退款相关
            ProdEffectRespParam prodOrderRefundParam = prodOrderRefundMap.get(respParam.getProdId());

            if (Objects.isNull(prodFlowParam) && Objects.isNull(prodOrderParam) && Objects.isNull(prodOrderRefundParam)) {
                iterator.remove();
            }
        }
        Set<Long> ids = respParams.stream().map(ProdEffectRespParam::getProdId).collect(Collectors.toSet());
        if (ids.isEmpty()) {
            return pages;
        }
        if (allProd) {
            pages.setRecords(productMapper.listProdByParam(param, ids));
        } else {
            pages = productMapper.pageProdByParam(page, param, ids);
        }
        List<Long> prodIdList = pages.getRecords().stream().map(ProdEffectRespParam::getProdId).collect(Collectors.toList());
        Map<Long, ProdLang> prodLangMap = langManager.getProdLangMap(prodIdList);
        for (ProdEffectRespParam prodEffectRespParam : pages.getRecords()) {
            ProdLang prodLang = prodLangMap.get(prodEffectRespParam.getProdId());
            if (Objects.nonNull(prodLang)) {
                prodEffectRespParam.setProdName(prodLang.getProdName());
            }
        }
        for (ProdEffectRespParam temp : pages.getRecords()) {
            // 商品相关数据
            ProdEffectRespParam prodFlowParam = prodFlowMap.get(temp.getProdId());
            //订单相关
            ProdEffectRespParam prodOrderParam = prodOrderMap.get(temp.getProdId());
            //退款相关
            ProdEffectRespParam prodOrderRefundParam = prodOrderRefundMap.get(temp.getProdId());

            if (Objects.nonNull(prodFlowParam)) {
                // 加购件数
                temp.setAddCart(prodFlowParam.getAddCart());
                // 加购人数
                temp.setAddCartPerson(prodFlowParam.getAddCartPerson());
                // 曝光人数
                temp.setExposePersonNum(prodFlowParam.getExposePersonNum());
                // 曝光次数
                temp.setExpose(prodFlowParam.getExpose());
            }

            if (Objects.nonNull(prodOrderParam)) {
                // 商品下单人数
                temp.setPlaceOrderPerson(prodOrderParam.getPlaceOrderPerson());
                // 支付人数
                temp.setPayPerson(prodOrderParam.getPayPerson());
                // 单品转化率 = 商品付款人数/商品访客人数
                temp.setSingleProdRate(divAverage(temp.getPayPerson(), temp.getExposePersonNum(), 4));
                // 商品下单数
                temp.setPlaceOrderNum(prodOrderParam.getPlaceOrderNum());
                // 支付商品件数
                temp.setPayNum(prodOrderParam.getPayNum());
                // 商品下单金额
                temp.setPlaceOrderAmount(prodOrderParam.getPlaceOrderAmount());
                // 商品支付金额
                temp.setPayAmount(setDefaultDouble(prodOrderParam.getPayAmount()));
            }

            if (Objects.nonNull(prodOrderRefundParam)) {
                // 申请退款订单数
                temp.setRefundNum(prodOrderRefundParam.getRefundNum());
                // 申请退款人数
                temp.setRefundPerson(prodOrderRefundParam.getRefundPerson());
                // 成功退款订单数
                temp.setRefundSuccessNum(prodOrderRefundParam.getRefundSuccessNum());
                // 成功退款人数
                temp.setRefundSuccessPerson(prodOrderRefundParam.getRefundSuccessPerson());
                // 成功退款金额
                temp.setRefundSuccessAmount(prodOrderRefundParam.getRefundSuccessAmount());
                // 退款率 = 成功退款订单数/申请退款订单数
                temp.setRefundSuccessRate(divAverage(temp.getRefundSuccessNum(), temp.getRefundNum(), 4));
            }

        }
        return pages;
    }

    private Set<Long> getFlowProdId(Integer dateType, Date startTime, Date endTime, Long shopId) {
        Set<Long> prodIdSet = new HashSet<>();
        if (Objects.equals(1, dateType)) {
            List<FlowLog> flowLogList = flowLogService.getFlowLogListByCache();
            List<Long> prodIds = flowLogList.stream()
                    .filter(flowLog -> FlowLogPageEnum.isProdInfo(flowLog.getPageId()) && StrUtil.isNotBlank(flowLog.getBizData()))
                    .map(flowLog -> Long.valueOf(flowLog.getBizData())).collect(Collectors.toList());
            prodIdSet.addAll(prodIds);
        } else {
            List<String> prodIds = flowPageAnalysisMapper.getProdIdsByTime(startTime, endTime, shopId);
            Pattern pattern = compile("[0-9]+");
            for (String prodId : prodIds) {
                if (pattern.matcher(prodId).matches()) {
                    prodIdSet.add(Long.valueOf(prodId));
                }
            }
        }
        if (CollUtil.isEmpty(prodIdSet)) {
            return null;
        }
        return prodIdSet;
    }

    private List<ProdEffectRespParam> getProdFlowData(Integer dateType, List<Long> prodIds, Date startTime, Date endTime) {
        List<ProdEffectRespParam> prodFlowList = new ArrayList<>();
        // 加购件数、加购人数、曝光人数、曝光次数、访客数
        if (Objects.equals(1, dateType)) {
            List<FlowLog> flowLogList = flowLogService.getFlowLogListByCache();
            Map<String, List<FlowLog>> flowLogMap = flowLogList.stream()
                    .filter(flowLog ->
                            (FlowLogPageEnum.isProdInfo(flowLog.getPageId()) || Objects.equals(flowLog.getVisitType(), FlowVisitEnum.SHOP_CAT.value()))
                                    && Objects.nonNull(flowLog.getBizData())
                                    && prodIds.contains(Long.valueOf(flowLog.getBizData())))
                    .collect(Collectors.groupingBy(FlowLog::getBizData));
            for (String key : flowLogMap.keySet()) {
                List<FlowLog> flowLogs = flowLogMap.get(key);
                ProdEffectRespParam prodEffectRespParam = new ProdEffectRespParam();
                int addCart = 0;
                Set<String> addCartPerson = new HashSet<>();
                int expose = 0;
                Set<String> exposePersonNum = new HashSet<>();
                for (FlowLog flowLog : flowLogs) {
                    if (Objects.equals(flowLog.getVisitType(), FlowVisitEnum.SHOP_CAT.value())) {
                        addCart = addCart + flowLog.getNums();
                        addCartPerson.add(flowLog.getUserId());
                    } else if (FlowVisitEnum.isVisitOrShare(flowLog.getVisitType())) {
                        expose++;
                        if (Objects.nonNull(flowLog.getUserId())) {
                            exposePersonNum.add(flowLog.getUserId());
                        } else {
                            exposePersonNum.add(flowLog.getUuid());
                        }
                    }
                }
                prodEffectRespParam.setProdId(Long.valueOf(key));
                //加购件数
                prodEffectRespParam.setAddCart(addCart);
                // 加购人数
                prodEffectRespParam.setAddCartPerson(addCartPerson.size());
                // 曝光人数
                prodEffectRespParam.setExposePersonNum(exposePersonNum.size());
                // 曝光次数
                prodEffectRespParam.setExpose(expose);

                prodFlowList.add(prodEffectRespParam);
            }
        } else {
            prodFlowList = flowPageAnalysisMapper.getProdEffectByDateAndProdIds(prodIds, startTime, endTime);
        }
        return prodFlowList;
    }

    @Override
    public List<ProdSingleTrendParam> getSingleProdTrend(Long prodId, ProdEffectParam param) {
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        List<DateParam> dates = DateUtils.findEveryDays(startTime, endTime);
        List<ProdSingleTrendParam> resList = new ArrayList<>();
        for (DateParam date : dates) {
            ProdSingleTrendParam res = new ProdSingleTrendParam();
            res.setCurrentDay(DateUtils.dateToStrYmd(date.getStartTime()));
            param.setStartTime(date.getStartTime());
            param.setEndTime(date.getEndTime());
            // 浏览量
            res.setBrowse(setDefaultZero(flowPageAnalysisMapper.countProdExposeNumByParam(prodId, param.getStartTime(), param.getEndTime())));
            // 访客数
            res.setVisitor(setDefaultZero(flowPageAnalysisMapper.countProdVisitorNumByProdId(prodId, param.getStartTime(), param.getEndTime())));
            // 付款人数
            res.setPayPerson(orderItemMapper.countPayPerson(prodId, param));
            // 付款商品件数
            res.setPayNum(setDefaultZero(productMapper.countPayNum(prodId, param)));
            resList.add(res);
        }
        return resList;
    }


    private Double refundRate(Integer a, Integer b) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b);
    }

    public Integer setDefaultZero(Integer data) {
        if (Objects.isNull(data)) {
            return 0;
        }
        return data;
    }

    public Long setDefaultZero(Long data) {
        if (Objects.isNull(data)) {
            return 0L;
        }
        return data;
    }

    public Double setDefaultDouble(Double data) {
        if (Objects.isNull(data)) {
            return 0.0;
        }
        return data;
    }

    private Double divAverage(Integer a, Integer b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    private Double divAverage(Double a, Long b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    private Double divAverage(Double a, Double b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    @Override
    public IPage<Product> pageProducts(PageParam<Product> page, ProductParam product) {
        return productMapper.pageProducts(page, product);
    }

    @Override
    public IPage<Product> pageByLang(PageParam<Product> page, ProductParam product) {
        IPage<Product> productIPage = productMapper.pageByLang(page, product);
        langManager.getProdLang(productIPage.getRecords());
        return productIPage;
    }

    @Override
    public List<Product> recoveryPreSaleProd() {
        List<Product> products = list(new LambdaUpdateWrapper<Product>().eq(Product::getPreSellStatus, 1).lt(Product::getPreSellTime, new Date()));
        if (CollectionUtils.isEmpty(products)) {
            return null;
        }
        productMapper.updatePreSale(products);
        return products;
    }

//    @Override
//    public IPage<ProductTagParam> pageByLangAndTag(PageParam<Product> page, ProductTagParam product, Integer isContain) {
//        return productMapper.pageByLangAndTag(page,product,isContain);
//    }

    @Override
    public List<Product> listProdByIdsAndType(ProductParam product) {
        return productMapper.listProdByIdsAndType(product);
    }

    @Override
    public List<Product> getProductListBySpuIds(Set<Long> prodIds) {
        if (CollectionUtil.isEmpty(prodIds)) {
            return new ArrayList<>();
        }
        List<Product> prodList = productMapper.getProductListBySpuIds(prodIds);
        langManager.getProdLang(prodList);
        return prodList;
    }

    @Override
    public IPage<Product> canDistributionProdPage(PageParam<Product> page, ProductParam product) {
        IPage<Product> productPage = productMapper.canDistributionProdPage(page, product);
        langManager.getProdLang(productPage.getRecords());
        return productPage;
    }

    @Override
    public void updateProductType(Long prodId, Integer prodType) {
        if (Objects.isNull(prodId)) {
            return;
        }
        bathUpdateProductType(Collections.singletonList(prodId), prodType);
    }

    @Override
    public void bathUpdateProductType(List<Long> prodIds, Integer prodType) {
        if (CollUtil.isEmpty(prodIds)) {
            return;
        }
        productMapper.bathUpdateProductType(prodIds, prodType);
        removeProductCacheByProdIds(prodIds);
    }

    @Override
    public Map<Long, Product> getProdDeliveryTemplateIdByProdIds(List<Long> prodIds) {
        List<Product> products = productMapper.getProdDeliveryTemplateIdByProdIds(prodIds);
        return products.stream().collect(Collectors.toMap(Product::getProdId, p -> p));
    }

    @Override
    public Map<Long, Product> getMapByProdIds(List<Long> prodIds) {
        return productMapper.getMapByProdIds(prodIds);
    }

    @Override
    public int getProductNum(Long shopId, Integer status) {
        return productMapper.getProductNum(shopId,status);
    }

    @Override
    public List<ProductBO> listProdStockAndSold(List<Long> prodIds) {
        if (CollUtil.isEmpty(prodIds)) {
            return new ArrayList<>();
        }
        return productMapper.listEsProdSoldAndStock(prodIds);
    }

    @Override
    public List<Product> getSynchronizationprodList(Long source,Long shopId) {
        return productMapper.getSynchronizationprodList(source,shopId);
    }

    @Override
    public PersonnftProdVo getPersonnftProdById(Long prodId) {
        PersonnftProdVo personnftProdVo = new PersonnftProdVo();
        Product product = productMapper.selectById(prodId);
        personnftProdVo.setPic(product.getPic());
        personnftProdVo.setProdName(product.getProdName());
        personnftProdVo.setChainCode(product.getChain());
        personnftProdVo.setChannelCode(product.getChannelCode());
        ProdNft dataByProdId = prodNftService.getDataByProdId(prodId);
        ProdLevel prodLevelData = prodLevelService.getById(dataByProdId.getLevelId());
        personnftProdVo.setProdLevel(prodLevelData);
        personnftProdVo.setDenomId(dataByProdId.getDenomId());
        personnftProdVo.setDenomName(dataByProdId.getDenomName());
        personnftProdVo.setAttr(dataByProdId.getAttr());
        personnftProdVo.setAuthorName(dataByProdId.getAuthorName());
        personnftProdVo.setIssueName(dataByProdId.getIssueName());
        return personnftProdVo;
    }

    @Override
    public Product getSynchronizationprod(String chainCode, String channelCode, String sourceId) {
        return productMapper.getSynchronizationprod(chainCode,channelCode,sourceId);
    }

    @Override
    public List<Long> prodIdsByRightsList() {
        return productMapper.prodIdsByRightsList();
    }

    @Override
    public void changeStatusByProdIds(List<Long> pIds, Integer status) {
        productMapper.changeStatusByProdIds(pIds, status);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateProdAndSkuStock(Long prodId, Long skuId, Integer stocks) {
        if (skuService.updateSkuStocks(skuId, stocks) < 1) {
            return false;
        }
        if (prodExtensionService.updateProdStocks(prodId) < 1) {
            return false;
        }
        eventPublisher.publishEvent(new EsProductUpdateEvent(prodId, null, EsOperationType.UPDATE));
        return true;
    }

    @Override
    public IPage<Product> prodSkuPage(PageParam<Product> page, ProductParam product) {
        List<Product> products = productMapper.prodSkuPage(new PageAdapter(page), product);
        langManager.getProdLang(products);
        page.setRecords(products);
        page.setTotal(productMapper.countProdSkuList(new PageAdapter(page), product));
        return page;
    }

    @Override
    public List<Product> prodAndSkuInfo(List<Long> prodIds, List<Long> skuIds) {
        List<Product> products = productMapper.prodAndSkuInfo(prodIds, skuIds);
        langManager.getProdLang(products);
        return products;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleAuditProd(Product dbProduct, OfflineHandleEvent offlineHandleEvent) {
        int handleStatus = offlineHandleEvent.getStatus();
        if (Objects.equals(handleStatus, OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())) {
            // 审核通过
            dbProduct.setStatus(ProdStatusEnums.NORMAL.getValue());
            updateById(dbProduct);
        } else if (Objects.equals(handleStatus, OfflineHandleEventStatus.OFFLINE_BY_PLATFORM.getValue())) {
            // 审核不通过,平台下线
            offlineHandleEvent.setHandleType(OfflineHandleEventType.PROD.getValue());
            offlineHandleEvent.setHandleId(dbProduct.getProdId());
            offlineHandleEvent.setCreateTime(new Date());
            offlineHandleEvent.setShopId(dbProduct.getShopId());
            offlineHandleEvent.setStatus(handleStatus);
            offlineHandleEventService.save(offlineHandleEvent);
            productMapper.updateToOffline(dbProduct.getProdId());
        }
    }

    @Override
    public List<Product> listProdAndSku(List<Long> prodIds) {
        List<Product> products = productMapper.listProdAndSku(prodIds);
        langManager.getProdLang(products);
        return products;
    }

    @Override
    public int updateStocks(Long prodId) {
        return prodExtensionService.updateProdStocks(prodId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Product> handleExpireVirtualProd() {
        List<Product> products = list(new LambdaUpdateWrapper<Product>()
                .eq(Product::getMold, 1)
                .eq(Product::getStatus, ProdStatusEnums.NORMAL.getValue())
                .eq(Product::getWriteOffTime, 0)
                .lt(Product::getWriteOffEnd, new Date()));
        if (CollectionUtils.isEmpty(products)) {
            return null;
        }
        for (Product product : products) {
            product.setStatus(ProdStatusEnums.SHOP_OFFLINE.getValue());
            updateById(product);
            // 如果是商品下架操作
            // 商品状态改变时发送事件到活动，让活动下线
            applicationContext.publishEvent(new ProdChangeStatusEvent(product, product.getStatus()));
//            applicationContext.publishEvent(new EsProductUpdateEvent(product.getProdId(),null, EsOperationType.SAVE));
        }
        return products;
    }

    private void stockBillLogChange(ProductParam productParam, Product product, List<Sku> insertSkuList, List<Sku> addStockSkuList, List<Sku> reduceStockSkuList) {
        // 记录普通商品通过编辑改变的库存记录
        if (CollUtil.isNotEmpty(insertSkuList)) {
            // 记录新增的sku库存初始化
            StockBillLog stockBillLog = new StockBillLog();
            stockBillLog.setShopId(product.getShopId());
            stockBillLog.setEmployeeId(productParam.getEmployeeId());
            stockBillLog.setMakerMobile(productParam.getEmployeeMobile());
            stockBillLog.setStockBillType(StockBillType.INITIALIZE.value());
            applicationContext.publishEvent(new StockBillChangeEvent(stockBillLog, insertSkuList));
        }
        if (CollUtil.isNotEmpty(addStockSkuList)) {
            // 记录库存编辑增加记录
            StockBillLog stockBillLog = new StockBillLog();
            stockBillLog.setShopId(product.getShopId());
            stockBillLog.setEmployeeId(productParam.getEmployeeId());
            stockBillLog.setMakerMobile(productParam.getEmployeeMobile());
            stockBillLog.setStockBillType(StockBillType.EDIT_STORAGE.value());
            applicationContext.publishEvent(new StockBillChangeEvent(stockBillLog, addStockSkuList));
        }
        if (CollUtil.isNotEmpty(reduceStockSkuList)) {
            // 记录库存编辑减少记录
            StockBillLog stockBillLog = new StockBillLog();
            stockBillLog.setShopId(product.getShopId());
            stockBillLog.setEmployeeId(productParam.getEmployeeId());
            stockBillLog.setMakerMobile(productParam.getEmployeeMobile());
            stockBillLog.setStockBillType(StockBillType.EDIT_OUTBOUND.value());
            applicationContext.publishEvent(new StockBillChangeEvent(stockBillLog, reduceStockSkuList));
        }
    }

    private void cannotEdit(Product dbProduct) {
        if (Objects.isNull(dbProduct.getProdType())) {
            return;
        }
        if (dbProduct.getProdType().equals(ProdType.PROD_TYPE_GROUP.value())) {
            // 商品正在参与拼团活动，无法修改规格
            throw new YamiShopBindException("yami.product.join.group");
        }
        if (dbProduct.getProdType().equals(ProdType.PROD_TYPE_SECKILL.value())) {
            // 商品正在参与秒杀活动，无法修改规格
            throw new YamiShopBindException("yami.product.join.seckill");
        }
    }

    private void setSkuName(List<ProdLangParam> prodLangList, List<Sku> skuList) {
        Map<Integer, String> prodNameMap = prodLangList.stream().collect(Collectors.toMap(ProdLangParam::getLang, ProdLangParam::getProdName));
        for (Sku sku : skuList) {
            for (SkuLang skuLang : sku.getSkuLangList()) {
                String prodName = prodNameMap.get(skuLang.getLang());
                if (StrUtil.isBlank(prodName)) {
                    continue;
                }
                if (StrUtil.isBlank(skuLang.getSkuName())) {
                    skuLang.setProdName(prodName);
                } else {
                    skuLang.setProdName(prodName + " " + skuLang.getSkuName());
                }
            }
        }
    }

    private void checkProdLang(List<ProdLangParam> prodLangList) {
        Integer lang = langManager.getDefaultLang();
        if (CollUtil.isEmpty(prodLangList)) {
            throw new YamiShopBindException("商品语言列表不能为空");
        }
        boolean containsMaster = false;
        for (ProdLangParam prodLangParam : prodLangList) {
            if (Objects.equals(prodLangParam.getLang(), lang)) {
                containsMaster = true;
            }
            prodLangParam.setProdName(prodLangParam.getProdName().trim());
            if (StrUtil.isNotBlank(prodLangParam.getBrief())) {
                prodLangParam.setBrief(prodLangParam.getBrief().trim());
            }
        }
        if (!containsMaster) {
            throw new YamiShopBindException("语言数据已更新，请重新录入商品信息");
        }
    }


    private void saveLang(ProductParam productParam) {
        List<ProdLang> prodLangList = BeanUtil.mapAsList(productParam.getProdLangList(), ProdLang.class);
        for (ProdLang prodLang : prodLangList) {
            prodLang.setProdId(productParam.getProdId());
        }
        prodLangService.saveBatch(prodLangList);
    }

    private boolean updateProdSku(Product dbProduct, Product product, List<Long> dbSkuIds, Map<Long, Sku> dbSkuMap, List<Sku> skuList, boolean skuStatusChangeFlag, List<Sku> insertSkuList, List<Sku> addStockSkuList, List<Sku> reduceStockSkuList) {
        Integer totalStock = 0;
        // 如果是活动商品不能删除sku，还需要判断下是否删除了
        if(skuList.size() < dbSkuIds.size()){
            cannotEdit(dbProduct);
        }

        // 更新的sku数量
        int updateSkuCount = 0;

        for (Sku sku : skuList) {
            sku.setIsDelete(0);
            if (Objects.equals(sku.getStatus(), 1)) {
                totalStock += sku.getStocks();
            }
            // 如果数据库中原有sku就更新，否者就插入
            if (dbSkuIds.contains(sku.getSkuId())) {
                Sku dbSku = dbSkuMap.get(sku.getSkuId());
                if (!skuStatusChangeFlag) {
                    skuStatusChangeFlag = !Objects.equals(dbSku.getStatus(), sku.getStatus());
                }
                skuService.updateSku(sku);
                if (Objects.nonNull(sku.getChangeStock())) {
                    if (sku.getChangeStock() > 0) {
                        // 库存增加
                        addStockSkuList.add(sku);
                    }
                    if (sku.getChangeStock() < 0) {
                        // 库存减少
                        reduceStockSkuList.add(sku);
                    }
                    ++updateSkuCount;
                }
            } else {
                insertSkuList.add(sku);
            }
        }
        if (updateSkuCount != dbProduct.getSkuList().size() || skuStatusChangeFlag || CollUtil.isNotEmpty(insertSkuList)) {
            // sku规格发生 增加/删除/启用/禁用
            cannotEdit(dbProduct);
        }
        product.setTotalStocks(totalStock);
        // 批量插入sku
        if (CollectionUtil.isNotEmpty(insertSkuList)) {
            for (Sku sku : skuList) {
                sku.setProdId(product.getProdId());
            }
            skuService.insertBatchAndLang(insertSkuList);
        }
        return skuStatusChangeFlag;
    }

}
